/*
 * Created by Jaren at 2023/9/25 9:28
 */
import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/base/file/file_manager.dart';
import 'package:inmotion_protocol/base/protocol.dart';
import 'package:inmotion_protocol/base/vehicle_data.dart';
import 'package:inmotion_protocol/common/accessory_info.dart';
import 'package:inmotion_protocol/common/assistant_settings.dart';
import 'package:inmotion_protocol/common/bms_log_manager.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/common/fw_update_manager.dart';
import 'package:inmotion_protocol/common/media_file_upload_manager.dart';
import 'package:inmotion_protocol/common/mode.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/common/response.dart';
import 'package:inmotion_protocol/common/riding_statistics_helper.dart';
import 'package:inmotion_protocol/common/vehicle_info.dart';
import 'package:inmotion_protocol/elephant/bean/real_time_info.dart';
import 'package:inmotion_protocol/elephant/bean/settings.dart';
import 'package:inmotion_protocol/elephant/bean/statistics.dart';
import 'package:inmotion_protocol/elephant/constant.dart';
import 'package:inmotion_protocol/elephant/elephant_log_manager.dart';
import 'package:inmotion_protocol/elephant/factory/message_factory.dart';
import 'package:inmotion_protocol/elephant/message.dart';
import 'package:inmotion_protocol/elephant/util.dart';
import 'package:inmotion_protocol/lorin/bean/base/bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/base/tbox.dart';
import 'package:inmotion_protocol/lorin/bean/base/tire_pressure_sensor.dart';
import 'package:inmotion_protocol/lorin/bean/base/vehicle_real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/common/bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/common/date.dart';
import 'package:inmotion_protocol/lorin/bean/common/response/response.dart';
import 'package:inmotion_protocol/lorin/media/avatar_file_manager.dart';
import 'package:inmotion_protocol/protocol_worker.dart';
import 'package:inmotion_protocol/util/byte_util.dart';
import 'package:inmotion_protocol/util/date_time_util.dart';
import 'package:inmotion_protocol/util/device.dart';
import 'package:inmotion_protocol/util/log.dart';

class ElephantProtocol extends Protocol<ElephantMessage> {
  ElephantProtocol(super.protocolWorker, super.msgFactory);

  @override
  void setup(ProductModel model, VersionWrapper version) {
    productProperty.model = model;
    productProperty.versionWrapper = version;
    ProductProperty.setDefaultProperty(productProperty);
    msgFactory().init(productProperty);
  }

  /// A shortcut for protocolWorker().sendAndGetRsp() with suitable timeout param
  Future<ElephantMessage> _sendAndGetRsp(ElephantMessage msg,
      {int? timeoutMs = 400, int maxRetryTimes = 0}) {
    return protocolWorker()
        .sendAndGetRsp(msg, timeoutMs: timeoutMs, maxRetryTimes: maxRetryTimes);
  }

  /// A shortcut for Future.delayed(Duration(milliseconds: x))
  Future _delay([int waitingMs = 400]) {
    return Future.delayed(Duration(milliseconds: waitingMs));
  }

  @override
  Future<SettingsResponse> headlightOnOff(
      {bool? on, bool? lowBeamOn, bool? highBeamOn}) async {
    protocolWorker().send(ElephantMessageFactory.genWriteMsg(
        ElephantConstant.extraFuncLightState,
        ByteUtil.num2BytesLe(on == true ? 1 : 0, 1)));
    await _delay();
    return _sendAndGetRsp(ElephantMessageFactory.genRequestHeadlightStateMsg(),
            maxRetryTimes: 2)
        .then((rspMsg) {
      int state = ByteUtil.bytes2Uint16Le(rspMsg.data).value;
      return ((on == true && state == 1) || (on == false && state == 0))
          ? SettingsResponse.success()
          : SettingsResponse.unknown();
    });
  }

  @override
  Future<SettingsResponse> lock([bool lock = true]) async {
    protocolWorker().send(ElephantMessageFactory.genWriteMsg(
        lock
            ? ElephantConstant.extraFuncLock
            : ElephantConstant.extraFuncUnlock,
        Uint8ClampedList.fromList([1])));
    await _delay();
    var mode = await _sendAndGetRsp(
            ElephantMessageFactory.genRequestWorkModeMsg(),
            maxRetryTimes: 2)
        .then((rspMsg) => ERealTimeState.parseMode(rspMsg.data));
    return (lock && (mode == Mode.locked) || (!lock && (mode != Mode.locked)))
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  @override
  Future<SettingsResponse> powerOnOff([bool on = true]) async {
    await protocolWorker().send(ElephantMessageFactory.genPowerOffMsg());
    await _delay();
    await protocolWorker()
        .send(ElephantMessageFactory.genPowerOffMsg())
        .catchError((e) => SettingsResponse.success());
    await _delay();
    return SettingsResponse.success();
  }

  @override
  Future<SettingsResponse> lostMode([bool enable = true]) async {
    // 启用时，使用lock锁车代替开启lost mode
    if (enable) return lock(true);
    return SettingsResponse.success();
  }

  @override
  Future<EAllRealTimeInfo> requestAllRealTimeData() async {
    ERealTimeInfo realTimeInfo = ERealTimeInfo();
    ERealTimeState realTimeState = ERealTimeState();
    ERealTimeError realTimeError = ERealTimeError();

    var rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genRequestAllRealTimeInfoMsg());
    realTimeState.pcMode = ERealTimeState.parseMode(rspMsg.data, offset: 8);
    realTimeState.lockState =
        ByteUtil.bool2Uint4(realTimeState.pcMode == Mode.locked);
    realTimeInfo.batteryLevel =
        ByteUtil.toUint16(ByteUtil.bytes2Uint16Le(rspMsg.data, 14).value * 100);
    realTimeInfo.speed =
        ByteUtil.toInt16(ByteUtil.bytes2Int16Le(rspMsg.data, 22).value ~/ 10);

    _cachedHistoryStatistics?.calculate(realTimeInfo, _statisticsMocker);

    rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genRequestHeadlightStateMsg());
    realTimeState.headlightState =
        ByteUtil.toUint4(ByteUtil.bytes2Uint8Le(rspMsg.data).value);

    rspMsg =
        await _sendAndGetRsp(ElephantMessageFactory.genRequestErrorCodeMsg());
    realTimeError.originalValue = ByteUtil.bytes2Uint32Le(rspMsg.data);

    return EAllRealTimeInfo(realTimeInfo, realTimeState, realTimeError);
  }

  @override
  Future<VehicleSynthesizeRealTimeInfo> requestVehicleSynthesizeRealTimeInfo() {
    throw UnimplementedError();
  }

  @override
  Future<DeviceWrapper> requestDevicesId(List<int> devices) {
    return Future(() => DeviceWrapper());
  }

  @override
  Future<FirmwareState> requestFirmwareState() {
    throw UnimplementedError();
  }

  @override
  Future<VersionWrapper> requestFwVersion([int? target]) {
    throw UnimplementedError();
  }

  @override
  Future<Settings> requestSettings() async {
    ESettings settings = ESettings();
    // 踏板灵敏度，转向灵敏度，平衡零点，骑行模式，限速，总里程，后退超速报警开关
    var rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncTurningSensitivity,
            intData: 6),
        maxRetryTimes: 2);
    settings.turningSensitivity = ByteUtil.bytes2Uint16Le(rspMsg.data);
    settings.pedalSensitivity = ByteUtil.bytes2Uint16Le(rspMsg.data, 2);
    settings.angleZ =
        ByteUtil.toInt16(ByteUtil.bytes2Int16Le(rspMsg.data, 4).value * 10);

    rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncEnableSpeedLimit,
            intData: 1),
        maxRetryTimes: 2);
    settings.ridingMode =
        rspMsg.data[0] == 1 ? ERidingMode.newbie : ERidingMode.normal;

    if (settings.ridingMode == ERidingMode.normal) {
      settings.speedLimit = ByteUtil.toUint16(ESettings.speedLimitOnNormalMode);
    } else {
      rspMsg = await _sendAndGetRsp(
          ElephantMessageFactory.genReadMsg(
              ElephantConstant.extraFuncSpeedLimit,
              intData: 2),
          maxRetryTimes: 2);
      settings.speedLimit =
          ByteUtil.toUint16(ByteUtil.bytes2Uint16Le(rspMsg.data).value ~/ 10);
    }

    rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncLightEffectMode,
            intData: 6),
        maxRetryTimes: 2);
    settings.lightEffectMode = ByteUtil.bytes2Uint8Le(rspMsg.data);
    settings.wheelLightEffectState = ByteUtil.bytes2Uint8Le(rspMsg.data, 2);
    var colorIndex = ByteUtil.bytes2Uint8Le(rspMsg.data, 5).value;
    settings.lightEffectColor = ElephantUtil.colorIndex2Color(colorIndex);

    rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncTotalRideMileage,
            intData: 4),
        maxRetryTimes: 2);
    var totalRideMileage = ByteUtil.bytes2Uint32Le(rspMsg.data);
    settings.mileageNeed2Ride2SwitchNormalRidingMode =
        (1000 - totalRideMileage.value) ~/ 10;

    rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(ElephantConstant.extraFuncFeatures,
            intData: 2),
        maxRetryTimes: 2);
    var features = ByteUtil.bytes2Uint16Le(rspMsg.data).value;
    settings.backwardOverSpeedAlert = ByteUtil.bitValue(features, 4, 1);

    return settings;
  }

  @override
  Future<SettingsResponse> setTurningSensitivity(int sensitivity) async {
    await protocolWorker().send(ElephantMessageFactory.genWriteMsg(
        ElephantConstant.extraFuncTurningSensitivity,
        ByteUtil.num2BytesLe(sensitivity, 2)));
    await _delay();
    var rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncTurningSensitivity,
            intData: 2),
        maxRetryTimes: 2);
    return ByteUtil.bytes2Uint8Le(rspMsg.data).value == sensitivity
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  @override
  Future<SettingsResponse> setPedalSensitivity(int sensitivity,
      [int? sensitivity2]) async {
    await protocolWorker().send(ElephantMessageFactory.genWriteMsg(
        ElephantConstant.extraFuncPedalSensitivity,
        ByteUtil.num2BytesLe(sensitivity, 2)));
    await _delay();
    var rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncPedalSensitivity,
            intData: 2),
        maxRetryTimes: 1);
    return ByteUtil.bytes2Uint8Le(rspMsg.data).value == sensitivity
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  /// 助力模式平衡点
  /// [angle] int [-2000, 2000]
  @override
  Future<SettingsResponse> setPitchAngleZero(int angle) async {
    angle = angle ~/ 10; // 单位0.1°
    await protocolWorker().send(ElephantMessageFactory.genWriteMsg(
        ElephantConstant.extraFuncBalanceAngle,
        ByteUtil.num2BytesLe(angle, 2)));
    await _delay();
    var rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncBalanceAngle,
            intData: 2),
        maxRetryTimes: 1);
    return ByteUtil.bytes2Int16Le(rspMsg.data).value == angle
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  @override
  Future<SettingsResponse> setRidingMode(int mode, [param]) async {
    await protocolWorker().send(ElephantMessageFactory.genWriteMsg(
        ElephantConstant.extraFuncEnableSpeedLimit,
        ByteUtil.num2BytesLe(mode, 2)));
    await _delay();
    var rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncEnableSpeedLimit,
            intData: 2),
        maxRetryTimes: 1);
    return ByteUtil.bytes2Uint8Le(rspMsg.data).value == mode
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  @override
  Future<Uint8ClampedList> requestLightEffectMode() async {
    var rspMsg = await _sendAndGetRsp(
        ElephantMessageFactory.genReadMsg(
            ElephantConstant.extraFuncLightEffectMode,
            intData: 2),
        maxRetryTimes: 2);
    // return ByteUtil.bytes2Uint8Le(rspMsg.data).value;
    // TODO: 带Uint8ClampedList结果的函数requestLightEffectMode需要重命名
    return rspMsg.data;
  }

  @override
  Future<ProductProperty> requestProductProperty() async {
    var driverBoardVersion = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(
                ElephantConstant.extraFuncDriverBoardVersion,
                intData: 2),
            maxRetryTimes: 2)
        .then((rspMsg) =>
            "${rspMsg.data[1]}.${rspMsg.data[0] >> 4}.${rspMsg.data[0] & 0x0F}")
        .catchError((e) => e is MsgTimeoutException
            ? throw RequestProductPropertyFailedException
                .bySoftwareVersionTimeout()
            : throw RequestProductPropertyFailedException
                .bySoftwareVersionParseFailed());

    var sn = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(ElephantConstant.extraFuncSn,
                intData: 8),
            maxRetryTimes: 2)
        .then((rspMsg) => ByteUtil.bytes2HexString(rspMsg.data).toUpperCase())
        .catchError((e) {
      LogUtils.e("", e);
      e is MsgTimeoutException
          ? throw RequestProductPropertyFailedException.bySNTimeout()
          : throw RequestProductPropertyFailedException.bySNParseFailed();
    });

    var productModel = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(
                ElephantConstant.extraFuncProductModel,
                intData: 4),
            maxRetryTimes: 2)
        .then((rspMsg) => ProductModel.fromElephant(rspMsg.data))
        .catchError((e) {
      LogUtils.e("", e);
      e is MsgTimeoutException
          ? throw RequestProductPropertyFailedException.byModelTimeout()
          : throw RequestProductPropertyFailedException.byModelParseFailed();
    });

    var btVersion = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(
                ElephantConstant.extraFuncBtVersion,
                intData: 2),
            maxRetryTimes: 2)
        .then((rspMsg) =>
            "${rspMsg.data[1]}.${rspMsg.data[0] >> 4}.${rspMsg.data[0] & 0x0F}")
        .catchError((e) => e is MsgTimeoutException
            ? throw RequestProductPropertyFailedException
                .bySoftwareVersionTimeout()
            : throw RequestProductPropertyFailedException
                .bySoftwareVersionParseFailed());

    VersionWrapper versionWrapper = VersionWrapper();
    versionWrapper.put(DeviceUtils.ezcanDulWheelPcDevice,
        Version(Uint8(DeviceUtils.ezcanDulWheelPcDevice), btVersion, "", ""));
    versionWrapper.put(
        DeviceUtils.ezcanDulWheelMcDevice,
        Version(Uint8(DeviceUtils.ezcanDulWheelMcDevice), driverBoardVersion,
            "", ""));
    return ProductProperty(sn, productModel, null, versionWrapper);
  }

  @override
  Future<ProductProperty> requestProductPropertyV2() {
    throw UnimplementedError(
        "requestProductPropertyV2 is not implemented in ElephantProtocol");
  }

  @override
  Future<RealTimeError> requestRealTimeError() async {
    ERealTimeError realTimeError = ERealTimeError();
    var rspMsg = await _sendAndGetRsp(
            ElephantMessageFactory.genRequestErrorCodeMsg(),
            maxRetryTimes: 2)
        .catchError((error) => throw error);
    realTimeError.originalValue = ByteUtil.bytes2Uint32Le(rspMsg.data);
    return realTimeError;
  }

  @override
  Future<RealTimeInfo> requestRealTimeInfo() async {
    ERealTimeInfo realTimeInfo = ERealTimeInfo();
    var rspMsg = await _sendAndGetRsp(
            ElephantMessageFactory.genRequestRealTimeInfoMsg(),
            maxRetryTimes: 2)
        .catchError((error) => throw error);

    realTimeInfo.batteryLevel =
        ByteUtil.toUint16(ByteUtil.bytes2Uint16Le(rspMsg.data, 0).value * 100);
    realTimeInfo.speed =
        ByteUtil.toInt16(ByteUtil.bytes2Int16Le(rspMsg.data, 8).value ~/ 10);

    _cachedHistoryStatistics?.calculate(realTimeInfo, _statisticsMocker);
    return realTimeInfo;
  }

  @override
  Future<RealTimeState> requestRealTimeState() async {
    ERealTimeState realTimeState = ERealTimeState();

    var rspMsg = await _sendAndGetRsp(
            ElephantMessageFactory.genRequestWorkModeMsg(),
            maxRetryTimes: 2)
        .catchError((error) => throw error);
    realTimeState.pcMode = ERealTimeState.parseMode(rspMsg.data, offset: 0);
    realTimeState.lockState =
        ByteUtil.bool2Uint4(realTimeState.pcMode == Mode.locked);

    rspMsg = await _sendAndGetRsp(
            ElephantMessageFactory.genRequestHeadlightStateMsg(),
            maxRetryTimes: 2)
        .catchError((error) => throw error);
    realTimeState.headlightState =
        ByteUtil.toUint4(ByteUtil.bytes2Uint8Le(rspMsg.data).value);

    return realTimeState;
  }

  EHistoryStatistics? _cachedHistoryStatistics;
  int _cachedHistoryStatisticsTimestamp = 0;
  final StatisticsMocker _statisticsMocker = StatisticsMocker();

  @override
  Future<TotalStatistics> requestTotalStatistics() async {
    ETotalStatistics totalStatistics = ETotalStatistics();
    _cachedHistoryStatistics ??= EHistoryStatistics();
    var rspMsg = await _sendAndGetRsp(
            ElephantMessageFactory.genRequestStatisticsInfoMsg(),
            maxRetryTimes: 2)
        .catchError((error) => throw error);
    totalStatistics.mileage = ByteUtil.toUint32(
        (ByteUtil.bytes2Uint32Le(rspMsg.data, 0).value +
                ByteUtil.bytes2Uint32Le(rspMsg.data, 4).value +
                ByteUtil.bytes2Uint32Le(rspMsg.data, 8).value) ~/
            10);
    totalStatistics.rideTime = ByteUtil.toUint32(
        (ByteUtil.bytes2Uint32Le(rspMsg.data, 18).value +
                ByteUtil.bytes2Uint32Le(rspMsg.data, 22).value +
                ByteUtil.bytes2Uint32Le(rspMsg.data, 26).value) ~/
            10);

    // 缓存单次统计信息
    _cachedHistoryStatistics!.mileage = ByteUtil.toUint16(
        (ByteUtil.bytes2Uint16Le(rspMsg.data, 12).value +
                ByteUtil.bytes2Uint16Le(rspMsg.data, 14).value +
                ByteUtil.bytes2Uint16Le(rspMsg.data, 16).value) ~/
            10);
    _cachedHistoryStatistics!.rideTime = ByteUtil.toUint16(
        (ByteUtil.bytes2Uint16Le(rspMsg.data, 36).value +
                ByteUtil.bytes2Uint16Le(rspMsg.data, 38).value) ~/
            10);
    _cachedHistoryStatisticsTimestamp = DateTimeUtil.current();
    return totalStatistics;
  }

  @override
  Future<HistoryStatistics> requestCurrentStatistics() async {
    if (_isHistoryStatisticsCacheValid()) return _cachedHistoryStatistics!;
    await requestTotalStatistics().catchError((error) => throw error);
    return _cachedHistoryStatistics!;
  }

  bool _isHistoryStatisticsCacheValid() {
    // 5s内不过期
    return _cachedHistoryStatistics != null &&
        (DateTimeUtil.current() - _cachedHistoryStatisticsTimestamp <=
            5 * 1000);
  }

  @override
  Future<SettingsResponse> backwardOverspeedAlterOnOff([bool on = true]) async {
    var rspMsg = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(
                ElephantConstant.extraFuncFeatures,
                intData: 1),
            maxRetryTimes: 1)
        .catchError((error) => throw error);
    int originalValue = rspMsg.data[0];

    /// 后退超速报警位于bit4
    int newValue = on ? (originalValue | 0x10) : (originalValue & 0xEF);
    await protocolWorker()
        .send(ElephantMessageFactory.genWriteMsg(
            ElephantConstant.extraFuncFeatures,
            ByteUtil.num2BytesLe(newValue, 1)))
        .catchError((error) => throw error);
    await _delay();
    rspMsg = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(
                ElephantConstant.extraFuncFeatures,
                intData: 1),
            maxRetryTimes: 1)
        .catchError((error) => throw error);
    var backwardOverspeedState = (rspMsg.data[0] & 0x10) != 0;
    return on == backwardOverspeedState
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  @override
  Future<SettingsResponse> sideWheelLightEffectOnOff([bool on = true]) async {
    int targetValue = on ? 1 : 0;
    await protocolWorker()
        .send(ElephantMessageFactory.genWriteMsg(
            ElephantConstant.extraFuncSideWheelLightEffectState,
            ByteUtil.num2BytesLe(targetValue, 1)))
        .catchError((error) => throw error);
    await _delay();
    var rspMsg = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(
                ElephantConstant.extraFuncSideWheelLightEffectState,
                intData: 1),
            maxRetryTimes: 1)
        .catchError((error) => throw error);
    return rspMsg.data[0] == targetValue
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  @override
  Future<SettingsResponse> setLightEffectMode(
      {bool? onOff, int? mode, int? paramColor, int? paramMode}) async {
    if (mode == null && paramColor == null)
      throw InvalidParamException(
          "Param [mode] and [paramColor] couldn't be both null!");

    /// 氛围灯模式
    if (mode != null) {
      protocolWorker()
          .send(ElephantMessageFactory.genWriteMsg(
              ElephantConstant.extraFuncLightEffectMode,
              ByteUtil.num2BytesLe(mode, 1)))
          .catchError((error) => throw error);
      await _delay();
      var rspMsg = await protocolWorker()
          .sendAndGetRsp(
              ElephantMessageFactory.genReadMsg(
                  ElephantConstant.extraFuncLightEffectMode,
                  intData: 1),
              maxRetryTimes: 1)
          .catchError((error) => throw error);
      return rspMsg.data[0] == mode
          ? SettingsResponse.success()
          : SettingsResponse.unknown();
    }

    /// 氛围灯颜色
    var colorIndex = ElephantUtil.color2ColorIndex(paramColor!);
    protocolWorker()
        .send(ElephantMessageFactory.genWriteMsg(
            ElephantConstant.extraFuncLightEffectColor,
            ByteUtil.num2Bytes(colorIndex, 2)))
        .catchError((error) => throw error);
    await _delay();
    var rspMsg = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(
                ElephantConstant.extraFuncLightEffectColor,
                intData: 2),
            maxRetryTimes: 1)
        .catchError((error) => throw error);
    return rspMsg.data[1] == colorIndex
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  @override
  Future<SettingsResponse> setSpeedLimit(int speedLimit,
      [int? speedLimit2]) async {
    speedLimit = speedLimit * 10;
    protocolWorker()
        .send(ElephantMessageFactory.genWriteMsg(
            ElephantConstant.extraFuncSpeedLimit,
            ByteUtil.num2BytesLe(speedLimit, 2)))
        .catchError((error) => throw error);
    await _delay();
    var rspMsg = await protocolWorker()
        .sendAndGetRsp(
            ElephantMessageFactory.genReadMsg(
                ElephantConstant.extraFuncSpeedLimit,
                intData: 2),
            maxRetryTimes: 1)
        .catchError((error) => throw error);
    return ByteUtil.bytes2Uint16Le(rspMsg.data).value == speedLimit
        ? SettingsResponse.success()
        : SettingsResponse.unknown();
  }

  @override
  Future<List<EsimModel>> requestTBoxEsimList() {
    throw UnimplementedError();
  }

  @override
  Future<TBoxInfo> requestTBoxRealTimeInfo() {
    throw UnimplementedError();
  }

  @override
  Future<bool> rebootTBox(int mode) {
    throw UnimplementedError();
  }

  @override
  Future<TBoxInfo> requestTBoxInfo() {
    throw UnimplementedError();
  }

  @override
  Future<StatisticsResponse> requestHistoryStatistics(int index, int count) {
    throw UnimplementedError();
  }

  @override
  Future<StatisticsInfoResponse> requestHistoryStatisticsInfo() {
    throw UnimplementedError();
  }

  @override
  Future<bool> activate(DateTime dateTime) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> assistBalanceOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> autoHeadlightOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> autoLowHighBeamOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> autoScreenOffOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> bermAngleModeOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> brakeFirstModeOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<bool> buildSecurityConnection() {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> checkFile(
      {int? target,
      int? fileHandle,
      int? offset,
      int? length,
      Uint8ClampedList? check}) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> closeFile({int? target, int? fileHandle}) {
    throw UnimplementedError();
  }

  @override
  AvatarFileManager createAvatarFileManager() {
    throw UnimplementedError();
  }

  @override
  AbsBmsLogManager createBMSLogManager() {
    throw UnimplementedError();
  }

  @override
  IFileManager createFileDownloadManager(FileConfig config) {
    throw UnimplementedError();
  }

  @override
  IFileManager createFileUploadManager(FileConfig config) {
    throw UnimplementedError();
  }

  @override
  FwUpdateManager createFwUpdateManager(LinkLayerDeviceHandler handler,
      RequiredManualOperationHandler requiredManualOperationHandler) {
    throw UnimplementedError();
  }

  @override
  LightEffectPkgFileUploadManager createLightEffectPkgUploadManager() {
    throw UnimplementedError();
  }

  @override
  ElephantLogManager createLogFileManager() {
    return ElephantLogManager(this);
  }

  @override
  RidingStatisticsHelper createRidingStatisticsHelper() {
    throw UnimplementedError();
  }

  @override
  SoundFileUploadManager createSoundFileUploadManager() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> cruiseOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> deleteDiySoundItem(int soundIndex) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> deleteFile(String path, {int? target}) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> deleteLightEffectPkg(int id) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> deleteSoundPack(int id) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> disableChargeDangerAlert() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> factoryReset({int level = 1}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> fanOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> fanQuietModeOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> getFile(
      {int? tab,
      int? target,
      int? fileHandle,
      int? offset,
      int? contentLength}) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> getFileCheck(
      {int? target, int? fileHandle, int? offset}) {
    throw UnimplementedError();
  }

  @override
  Future<FileListResponse> getFileList({Object? filter}) {
    throw UnimplementedError();
  }

  @override
  Future<List<int>> getLightEffectPkgIdList() {
    throw UnimplementedError();
  }

  @override
  Future<int> getRemainStorageCapacity({int diskIndex = 0}) {
    throw UnimplementedError();
  }

  @override
  Future<List<int>> getSoundItemIndexList() {
    throw UnimplementedError();
  }

  @override
  Future<List<int>> getSoundPackIdList({int? currentSoundPackId}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> gpsOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> hacOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> hdcOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> loadDetectOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> lowBatLevelProtectionModeOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> noLoadDetectOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> onePedalModeOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> openFile(
      {int? target, int? openType, String? name, int? type, int? tag}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> overSpeedWarningOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> playSoundItem(int index) {
    throw UnimplementedError();
  }

  @override
  Future<AbsBMSCellsVoltage> requestBMSCellsVoltage(int target) {
    throw UnimplementedError();
  }

  @override
  Future<Datetime> requestBMSDate(int which) {
    throw UnimplementedError();
  }

  @override
  Future<BMSFixedInfo> requestBMSFixedInfo(int which) {
    throw UnimplementedError();
  }

  @override
  Future<BMSAllRealTimeInfo> requestBMSRealTimeInfo(int which) {
    throw UnimplementedError();
  }

  @override
  Future<BatteryRealTimeInfo> requestBatteryRealTimeInfo() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> requestDeviceName() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> horn() {
    throw UnimplementedError();
  }

  @override
  Future prepareOnLinkLayerConnected(String deviceName,
      {String clientId = '', bool resetData = true}) {
    return Future(() => null);
  }

  @override
  Future<AbsCalibrationResultResponse> queryBatteryCalibrationResult() {
    throw UnimplementedError();
  }

  @override
  Future<AbsCalibrationResultResponse> queryCalibrationResult(int which) {
    throw UnimplementedError();
  }

  @override
  Future<AbsCalibrationResultResponse> queryHandleCalibrationResult(
      [int? which]) {
    throw UnimplementedError();
  }

  @override
  Future<AbsCalibrationResultResponse> queryIMUCalibrationResult() {
    throw UnimplementedError();
  }

  @override
  Future<AbsCalibrationResultResponse> queryMotorAutoCalibrationResult() {
    throw UnimplementedError();
  }

  @override
  Future<AbsCalibrationResultResponse> queryMotorSelfCheckResult() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> remainderRangeEstimateOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> renameFile(String filePath, String newFilePath) {
    throw UnimplementedError();
  }

  @override
  Future<AccessoryWrapper> requestAccessoriesInfo() {
    return Future(() => AccessoryWrapper());
  }

  @override
  Future<DateTime> requestActivatedTime() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> resetMotorAutoCalibrationEffect(
      {int hallOffset = 1, int hallSector = 1}) {
    throw UnimplementedError();
  }

  @override
  Future<void> respondQuickConnect() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> safeSpeedLimitOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setAccForce(int force, {int? type}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setAssistantMode(int mode, [param]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setAutoHeadlightBrightnessThr(
      int lowThr, int highThr) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setAutoLowHighBeamSwitchSpeedThr(int speedThr) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setBrakeForce(int force, {int? type}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setDeviceName(String name) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setDriveMode(int mode) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> setFileOffset({int? type, int? offset}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setHeadlightBrightness(
      {int? brightness, int? lowBeamBrightness, int? highBeamBrightness}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setLanguage(int language) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setLightEffectId(int id, [int? color]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setMaxChargeLevel(int level) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setMaxDcOutputLevel(int level) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setParkTime(int seconds) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setPassword(String pwd, [int? type]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setPasswordType(int type) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setSoundPackId(int id) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setSoundWaveSensitivity(int sensitivity) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setSpeedLimitOfAssistMode(int speedLimit) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setSpeedUnit(int unit) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setSpeedingBrakingSensitivity(
      int speeding, int braking) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setStandbyTime(int seconds) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setUSBMode(int mode) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setVolume(int volume) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setWarningLimitSpeed(int speed1, int speed2) {
    throw UnimplementedError();
  }

  @override
  Future<bool> bindTirePressureSensor(
      String sensorId) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> tirePressureWarningOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setLowTirePressureWarningThreshold(int threshold) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setLogoLightBrightness(int brightness) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setTurnSignalMode(int mode) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setBermAngle(int angle) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setOutputThreshold(int tiltBack, int warning1, int warning2) {
    throw UnimplementedError();
  }

  @override
  Future<List<TirePressureSensor>> searchTirePressureSensor() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> resetTirePressureSensorSearchResult() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> soundPackOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> soundWaveOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> speedingBrakingOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> spinKillOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startAccHandleCalibration() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startBalanceCalibration() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startBatteryCalibration() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startBrakeHandleCalibration() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startCalibration(int which) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startMotorAutoCalibration(
      {int hallOffsetCorrect = 1, int hallSectorCorrect = 1}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startMotorSelfCheck({int method = 1}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startTurningCalibration() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startUpdate(int target, {Uint8ClampedList? para}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> stopMotorAutoCalibration() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> stopMotorSelfCheck() {
    throw UnimplementedError();
  }

  @override
  Future<bool> syncRTC(DateTime? dateTime) {
    return Future(() => true);
  }

  @override
  Future<SettingsResponse> transportationModeOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> usbPowerOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> writeFile(Uint8ClampedList content,
      {int? tab,
      int? target,
      int? fileHandle,
      int? offset,
      int? contentLength}) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> writeForceUpdate(
      int level, String minVersion, String maxVersion) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> zeroSpeedupOnOff(
      [bool on = true, AbsAssistanceSettings? assistanceSettings]) {
    throw UnimplementedError();
  }

  @override
  Future<void> requestRebootHmic() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> twoBatteryMode([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> daytimeRunningLightOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startTransfer(int target, {Uint8ClampedList? para}) {
    throw UnimplementedError();
  }
  
  @override
  Future<SettingsResponse> showTboxInfoOnVehicleOnOff([bool on = true]) {
    throw UnimplementedError();
  }
  
  @override
  Future<SettingsResponse> tboxLowBatLevelWakeUpVehicleModeOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setMaxChargeCurrent(int currentAc220, int currentAc110) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setChargeLimitPercentage(int percentage) {
    throw UnimplementedError();
  }
}

class StatisticsMocker {
  int lastMaxSpeed = 0;

  void reset() {
    lastMaxSpeed = 0;
  }
}
